package com.bby.disk.manager.auth;

import cn.hutool.core.util.ObjectUtil;
import com.bby.common.exception.BBYException;
import com.bby.common.model.Permission;
import com.bby.common.model.UserGroup;
import com.bby.common.utils.BBYUtils;
import com.bby.common.utils.StatusCode;
import com.bby.disk.bean.vo.VirtualFileList;
import com.bby.disk.exception.BBYExceptionHandler;
import com.bby.disk.manager.virtual.VirtualDirectory;
import com.bby.disk.manager.virtual.VirtualManager;
import com.bby.disk.manager.virtual.VirtualObject;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.*;

/**
 * 每个文件的权限只针对此文件，包括文件夹
 * 校验权限，没有权限就抛异常，有权限则返回文件对象，所以函数不返回 null
 */
public class AuthorityManager {

    private static void auth(String userId, boolean ann, boolean user, boolean custom, VirtualObject file) throws BBYException {
        int flag = authNoException(userId,ann,user,custom,file);
        if (flag==1){
            return;
        }
        if (flag==0) throw BBYExceptionHandler.NON_AUTHORITY_EX;
        else if (flag==2) throw new BBYException(StatusCode.FILE_PASS_ERROR,"文件密码错误！");
        else throw new BBYException(StatusCode.FILE_NEED_PASS,"没有输入文件密码！");
    }
    private static int checkPW(String pw){
        ServletRequestAttributes attributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        if (attributes==null) return 3;
        String pwInput = attributes.getRequest().getHeader("filePw");
        if (BBYUtils.isEmpty(pwInput)) return 3;
        return pw.equals(pwInput)? 1:2;
    }
    private static boolean checkGroup(String userId,VirtualObject file){
        List<UserGroup> groups = VirtualManager.getUserGroup(file.getOwner());
        Permission permission = file.getPermission();
        Map<String,UserGroup> map = new HashMap<>();
        for (UserGroup group : groups) {
            map.put(group.getId(),group);
        }
        List<String> customGroups = permission.getCustomGroup();
        if (ObjectUtil.isNotEmpty(customGroups) && ObjectUtil.isNotEmpty(groups)) {
            // 判断用户组
            for (String id : customGroups) {
                UserGroup group = map.get(id);
                if (ObjectUtil.isNotEmpty(group) && group.content.contains(userId)) {
                    // 用户密码验证
                    return true;
                }
            }
        }
        return false;
    }
    // 0失败 1通过 2密码错误 3没密码
    private static int authNoException(String userId, boolean ann, boolean user, boolean custom,VirtualObject file) {
        Permission permission=file.getPermission();
        // 匿名
        if (BBYUtils.isEmpty(userId)){
            if (ann){
                // 匿名密码验证
                if (permission.getAnn().needPw && !BBYUtils.isEmpty(permission.getPw())){
                    return checkPW(permission.getPw());
                }else return 1;
            }
            return 0;
        }else {// 用户
            int flag = 0;
            if (user||ann) {// 匿名有权限的话，也通过
                // 用户密码验证
                if (permission.getUser().needPw && !BBYUtils.isEmpty(permission.getPw())){
                    // 密码验证不通过，还有用户组
                    flag=checkPW(permission.getPw());
                    if (flag==1) return 1;
                }else return 1;
            }
            // 用户组
            if (custom) {
                if (checkGroup(userId,file)){
                    if (permission.getCustom().needPw && !BBYUtils.isEmpty(permission.getPw())){
                        // 密码验证
                        return checkPW(permission.getPw());
                    }else return 1;
                }
            }
            return flag;
        }
    }

    /**
     * 判断文件的view权限
     */
    public static boolean canView(String userId,VirtualObject file){
        // 自己的，不用判断
        if (Objects.equals(userId, file.getOwner())){
            return true;
        }
        // 不是自己的文件,才需要判断权限
        Permission permission = file.getPermission();
        if (permission == null || !file.getPermission().isOpen() ) {
            return false;// 总开关没开
        }
        if (permission.getAnn().canView()) return true;
        if (!BBYUtils.isEmpty(userId)){
            if (permission.getUser().canView()) return true;
            if (permission.getCustom().canView()&&checkGroup(userId,file)){
                return true;
            }
        }
        return false;
    }
    /**
     * VirtualFileList 中只返回文件夹下可见的文件
     * @param userId
     * @param fileId
     * @throws BBYException
     */
    public static VirtualFileList list(String userId, String fileId) throws BBYException {
        VirtualDirectory dir = VirtualManager.findDirectory(fileId);
        List<VirtualObject> visible = new ArrayList<>();
        List<VirtualObject> files = VirtualManager.findFiles(dir.getFiles());
        VirtualFileList result = new VirtualFileList(dir);
        // 不是自己的文件,才需要判断权限
        if (!dir.getOwner().equals(userId)) {
            for (VirtualObject file : files) {
                Permission permission = file.getPermission();
                if (permission==null){
                    continue;
                }
                try {
                    auth(userId, permission.getAnn().canView(), permission.getUser().canView(), permission.getCustom().canView(), file);
                }catch (BBYException e){
                    continue;
                }
                visible.add(file);
            }
            result.setList(visible);
        }else {
            result.setList(files);
        }
        return result;
    }

    /**
     * 上传
     * @param userId 用户id
     * @param parent 新建文件夹/要上传文件 的父目录
     */
    public static VirtualDirectory create(String userId, String parent) throws BBYException {
        VirtualDirectory parentDir = VirtualManager.findDirectory(parent);
        // 只有在自己的网盘中才能设置权限
//        if ((userId == null || !userId.equals(parentDir.getOwner())) && file.getPermission()!=null) {
//            throw BBYExceptionHandler.NON_AUTHORITY_EX;
//        }
        // 不是自己的文件,才需要判断权限
        if (!parentDir.getOwner().equals(userId)) {
            Permission permission = parentDir.getPermission();
            if (permission == null) {
                throw BBYExceptionHandler.NON_AUTHORITY_EX;
            }
            auth(userId, permission.getAnn().canCreate(), permission.getUser().canCreate(), permission.getCustom().canCreate(), parentDir);
        }
        return parentDir;
    }

    /**
     * 删除，需要拥有文件夹下所有文件的权限
     * @param userId 用户id
     * @param fileId 要删除的文件id
     * @throws BBYException
     */
    public static void delete(String userId, String fileId) throws BBYException {
        VirtualObject file = VirtualManager.findFile(fileId);
        // 不是自己的文件,才需要判断权限
        if (!file.getOwner().equals(userId)) {
            Permission permission = file.getPermission();
            if (permission == null) {
                throw BBYExceptionHandler.NON_AUTHORITY_EX;
            }
            auth(userId, permission.getAnn().canDelete(), permission.getUser().canDelete(), permission.getCustom().canDelete(), file);
        }
        // 递归文件夹判断
        if (!file.isFile()){
            List<String> files = ((VirtualDirectory) file).getFiles();
            if (files==null || files.size()==0) return;
            for (String name : files) {
                delete(userId,name);
            }
        }
    }

    /**
     * 重命名
     * @param userId 用户id
     * @param fileId 要重命名的文件id
     */
    public static void rename(String userId, String fileId) throws BBYException {
        VirtualObject file = VirtualManager.findFile(fileId);
        // 不是自己的文件,才需要判断权限
        if (!file.getOwner().equals(userId)) {
            Permission permission = file.getPermission();
            if (permission == null) {
                throw BBYExceptionHandler.NON_AUTHORITY_EX;
            }
            auth(userId, permission.getAnn().canRename(), permission.getUser().canRename(), permission.getCustom().canRename(), file);
        }
    }

    /**
     * 需要拥有文件夹下所有文件的权限
     * @return
     */
    public static VirtualDirectory copyAndMove(String userId, String from, String to, boolean copy) throws BBYException {
        VirtualDirectory toFile = VirtualManager.findDirectory(to);
        // 判断to权限
        Permission permission = toFile.getPermission();
        if (!toFile.getOwner().equals(userId)) {
            // 不能跨网盘移动
            if (!copy){
                throw new BBYException("不能跨网盘移动文件！");
            }
            if (permission == null) {
                throw BBYExceptionHandler.NON_AUTHORITY_EX;
            }
            auth(userId, permission.getAnn().canCreate(), permission.getUser().canCreate(), permission.getCustom().canCreate(), toFile);
        }
        copyAndMove(userId,from,copy);
        return toFile;
    }
    private static void copyAndMove(String userId, String from, boolean copy) throws BBYException {
        VirtualObject fromFile = VirtualManager.findFile(from);
        Permission permission = fromFile.getPermission();

        // 判断from权限
        if (!fromFile.getOwner().equals(userId)) {
            if (permission == null) {
                throw BBYExceptionHandler.NON_AUTHORITY_EX;
            }
            if (copy){
                auth(userId, permission.getAnn().canCopy(), permission.getUser().canCopy(), permission.getCustom().canCopy(), fromFile);
            }else {
                auth(userId, permission.getAnn().canMove(), permission.getUser().canMove(), permission.getCustom().canMove(), fromFile);
            }
        }
        // 递归文件夹判断
        if (!fromFile.isFile()){
            List<String> files = ((VirtualDirectory) fromFile).getFiles();
            if (files==null||files.size()==0) return;
            for (String file : files) {
                copyAndMove(userId,file,copy);
            }
        }
    }

    /**
     * 下载
     * @param userId 用户id
     * @param fileId 要重命名的文件id
     */
    public static VirtualObject download(String userId, String fileId) throws BBYException {
        VirtualObject file = VirtualManager.findFile(fileId);
        // 不是自己的文件,才需要判断权限
        if (!file.getOwner().equals(userId)) {
            Permission permission = file.getPermission();
            if (permission == null) {
                throw BBYExceptionHandler.NON_AUTHORITY_EX;
            }
            auth(userId, permission.getAnn().canDownload(), permission.getUser().canDownload(), permission.getCustom().canDownload(), file);
        }
        return file;
    }

}
